using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.CodeDom.Compiler;
using Microsoft.VisualStudio.TextTemplating;

namespace T4MVCGen.Core
{
    public delegate void CountUpdate(object sender, CountEventArgs e);

	/// <summary>
	/// Generates C# and SQL code for accessing a database.
	/// </summary>
	public static class T4Generator
	{
		public static event CountUpdate DatabaseCounted;
		public static event CountUpdate TableCounted;

		/// <summary>
		/// Generates the SQL and C# code for the specified database.
		/// </summary>
		/// <param name="outputDirectory">The directory where the C# and SQL code should be created.</param>
		/// <param name="connectionString">The connection string to be used to connect the to the database.</param>
		/// <param name="grantLoginName">The SQL Server login name that should be granted execute rights on the generated stored procedures.</param>
		/// <param name="storedProcedurePrefix">The prefix that should be used when creating stored procedures.</param>
		/// <param name="createMultipleFiles">A flag indicating if the generated stored procedures should be created in one file or separate files.</param>
        /// <param name="projectName">The name of the project file to be generated.</param>
		/// <param name="targetNamespace">The namespace that the generated C# classes should contained in.</param>
		/// <param name="daoSuffix">The suffix to be applied to all generated DAO classes.</param>
        /// <param name="dtoSuffix">The suffix to be applied to all generated DTO classes.</param>
		public static void Generate(Options options)
		{
			List<T4GenTable> tableList = new List<T4GenTable>();
			string databaseName;
			string sqlPath;
			string csPath;
            
            IDbHelper _dbHelper = DbFactory.GetDbHelper((DatabaseType)options.databaseType);
            _dbHelper.FetchTables(options,out tableList, out databaseName, out sqlPath, out csPath);

			DatabaseCounted(null, new CountEventArgs(tableList.Count));

            // Generate the necessary SQL and C# code for each table
            int count = 0;
            if (tableList.Count > 0)
            {
                string controllersPath = Path.Combine(csPath, "Controllers");
                string modelsPath = Path.Combine(csPath, "Models");
                string viewsPath = Path.Combine(csPath, "Views");
                string repositoriesPath = Path.Combine(csPath, "Repositories");

                // Create the necessary directories
                Utility.CreateSubDirectory(sqlPath, true);
                Utility.CreateSubDirectory(csPath, true);
                Utility.CreateSubDirectory(controllersPath, true);
                Utility.CreateSubDirectory(modelsPath, true);
                Utility.CreateSubDirectory(viewsPath, true);
                Utility.CreateSubDirectory(repositoriesPath, true);

                foreach (T4GenTable table in tableList)
                {
                    ProcessTemplate("T4\\ControllerWithRepository.tt", table, options.projectName, options.targetNamespace, controllersPath, sqlPath, ".cs");
                    count++;
                    TableCounted(null, new CountEventArgs(count));

                }
            }

		}

        public static void ConnectDatabase(Options options)
        {
            List<string> tableList=new List<string>();
            string databaseName;
            IDbHelper _dbHelper= DbFactory.GetDbHelper((DatabaseType)options.databaseType);
            _dbHelper.FetchTableNames(options, out tableList,out databaseName);

            DatabaseCounted(null, new CountEventArgs(tableList.Count, tableList.ToArray<string>()));
        }



        static void ProcessTemplate(string templateFileName,T4GenTable table, string projectName, string targetNamespace,string csPath,string sqlPath,string fileExtensionValue)
        {
            if (string.IsNullOrEmpty(templateFileName))
            {
                throw new ArgumentNullException("the file name cannot be null");
            }
            if (!File.Exists(Utility.ResolveFilePath(templateFileName)))
            {
                throw new FileNotFoundException("the file cannot be found");
            }
            CustomTextTemplatingHost host = new CustomTextTemplatingHost();
            host.TemplateFileValue = Utility.ResolveFilePath(templateFileName);
            host.AreaName = string.Empty;
            host.ControllerRootName = table.Name;
            host.Namespace = targetNamespace;
            host.FileExtensionValue = fileExtensionValue;
            //Read the text template.
            string input = File.ReadAllText(templateFileName);

            IModel model = new ST4bbyModel(table.Name,targetNamespace,table);

            TextTemplatingSession session = new TextTemplatingSession();
            session["EntityName"] = targetNamespace;
            session["classname"] = table.Name;
            session["model"] = model;
            //session["table"] = table;
            var sessionHost = (ITextTemplatingSessionHost) host;
            sessionHost.Session = session;

            //Transform the text template.
            Engine engine = new Engine();
            string output = engine.ProcessTemplate(input, host);
            string outputFileName = host.ControllerName; // Path.GetFileNameWithoutExtension(templateFileName);
            outputFileName = Path.Combine(csPath, outputFileName); //Path.Combine(Path.GetDirectoryName(templateFileName), outputFileName);
            outputFileName = outputFileName + host.FileExtension;
            File.WriteAllText(outputFileName, output, host.FileEncoding);

            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            foreach (CompilerError error in host.Errors)
            {
                sb.Append(error.ToString());
            }
            if (sb.Length>0)
            {
                throw new Exception(sb.ToString());
            }
        }


	}
}
